package com.hhsj.ui.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import com.hhsj.ui.R;

/**
 * canvas.clipPath 当path为曲线的时候，无法处理锯齿效果
 * <p>
 * 增加一个操作类型 是否将背景clip
 */
public class RoundCornerFrameLayout extends FrameLayout {

    private RectF pathArc = new RectF();

    private Path boundPath = new Path();
    private RectF viewBound = new RectF();

    private Path borderPath = new Path();
    private RectF inViewBound = new RectF();

    private Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private boolean roundEnable = true;

    private RoundParams roundParams;

    public RoundCornerFrameLayout(Context context) {
        this(context, null);
    }

    public RoundCornerFrameLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundCornerFrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initRoundCornerAttrs(context, attrs);
    }

    private void initRoundCornerAttrs(@NonNull Context context, AttributeSet attr) {
        setWillNotDraw(false);

        roundParams = new RoundParams(this);

        TypedArray array = context.obtainStyledAttributes(attr, R.styleable.RoundCornerFrameLayout);
        if (array.hasValue(R.styleable.RoundCornerFrameLayout_roundAsCircle)) {
            roundParams.setRoundAsCircle(array.getBoolean(R.styleable.RoundCornerFrameLayout_roundAsCircle, false));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_clipBackground)) {
            roundParams.setClipBackground(array.getBoolean(R.styleable.RoundCornerFrameLayout_clipBackground, false));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_clipForeground)) {
            roundParams.setClipForeground(array.getBoolean(R.styleable.RoundCornerFrameLayout_clipForeground, false));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_borderEnable)) {
            roundParams.setBorderEnable(array.getBoolean(R.styleable.RoundCornerFrameLayout_borderEnable, false));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_roundCornerRadius)) {
            roundParams.setRoundCornerRadius(array.getDimension(R.styleable.RoundCornerFrameLayout_roundCornerRadius, 0.0F));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_roundTopLeft)) {
            roundParams.setRoundTopLeft(array.getBoolean(R.styleable.RoundCornerFrameLayout_roundTopLeft, false));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_roundTopRight)) {
            roundParams.setRoundTopRight(array.getBoolean(R.styleable.RoundCornerFrameLayout_roundTopRight, false));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_roundBottomLeft)) {
            roundParams.setRoundBottomLeft(array.getBoolean(R.styleable.RoundCornerFrameLayout_roundBottomLeft, false));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_roundBottomRight)) {
            roundParams.setRoundBottomRight(array.getBoolean(R.styleable.RoundCornerFrameLayout_roundBottomRight, false));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_roundingBorderWidth)) {
            roundParams.setRoundingBorderWidth(array.getDimension(R.styleable.RoundCornerFrameLayout_roundingBorderWidth, 0.0F));
        }

        if (array.hasValue(R.styleable.RoundCornerFrameLayout_roundingBorderColor)) {
            roundParams.setRoundingBorderColor(array.getColor(R.styleable.RoundCornerFrameLayout_roundingBorderColor, 0));
        }
        array.recycle();


    }


    @Override
    public void draw(Canvas canvas) {
        if (roundParams != null && roundParams.isClipBackground()) {
            beforeDraw(canvas);
        }
        super.draw(canvas);
        if (roundParams != null && roundParams.isClipForeground()) {
            afterDraw(canvas);
        }

        if (roundParams != null && roundParams.isBorderEnable()) {
            borderPaint.setColor(roundParams.getRoundingBorderColor());
            start(canvas);
            obtainBorder();
            canvas.drawPath(borderPath, borderPaint);
            completed(canvas);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (roundParams != null && !roundParams.isClipBackground()) {
            beforeDraw(canvas);
        }
        super.dispatchDraw(canvas);
        if (roundParams != null && !roundParams.isClipForeground()) {
            afterDraw(canvas);
        }
    }

    @Override
    public void onDrawForeground(Canvas canvas) {
        super.onDrawForeground(canvas);
    }

    private void beforeDraw(@NonNull Canvas canvas) {
        if (!roundEnable) {
            return;
        }
        start(canvas);
        applyBound(canvas, obtainBounds(), boundPath);
    }

    private void afterDraw(@NonNull Canvas canvas) {
        if (!roundEnable) {
            return;
        }
        completed(canvas);
    }

    private boolean ifRoundAsCircle(Path path) {
        if (!roundEnable) {
            return false;
        }
        return false;
    }

    private float getMinSize() {
        return Math.min(getWidth(), getHeight());
    }

    private void start(@NonNull Canvas canvas) {
        canvas.save();
        viewBound.left = getPaddingLeft();
        viewBound.top = getPaddingTop();
        viewBound.right = getWidth() - getPaddingRight();
        viewBound.bottom = getHeight() - getPaddingBottom();
        if (roundParams.isBorderEnable) {
            inViewBound.left = getPaddingLeft() + roundParams.getRoundingBorderWidth();
            inViewBound.top = getPaddingTop() + roundParams.getRoundingBorderWidth();
            inViewBound.right = getWidth() - getPaddingRight() - roundParams.getRoundingBorderWidth();
            inViewBound.bottom = getHeight() - getPaddingBottom() - roundParams.getRoundingBorderWidth();
        }
    }

    private boolean obtainBounds() {
        if (roundParams == null) {
            return false;
        }
        boundPath.setFillType(Path.FillType.WINDING);
        if (roundParams.roundAsCircle) {
            float radius = getMinSize() / 2;
            boundPath.addCircle(getWidth() / 2, getHeight() / 2, radius, Path.Direction.CW);
            return true;
        }
        final float radius = roundParams.getRoundCornerRadius();
        if (radius > 0 && isAnyCornerHasRound()) {
            //顺时针
            //左上角
            whenTopLeftRound(viewBound, boundPath, radius);
            //上直
            boundPath.lineTo(roundParams.isRoundTopRight ? viewBound.right - radius + radius : viewBound.right, viewBound.top);
            //右上角
            whenTopRightRound(viewBound, boundPath, radius);
            //右直
            boundPath.lineTo(viewBound.right, roundParams.isRoundBottomRight ? viewBound.bottom - radius : viewBound.bottom);
            //右下角
            whenBottomRightRound(viewBound, boundPath, radius);
            //下直
            boundPath.lineTo(roundParams.isRoundBottomLeft ? viewBound.left + radius : viewBound.left, viewBound.bottom);
            //左下角
            whenBottomLeftRound(viewBound, boundPath, radius);
            //左直
            boundPath.lineTo(viewBound.left, roundParams.isRoundTopLeft ? viewBound.top + radius : viewBound.top);
            return true;
        }

        return false;
    }

    private void obtainBorder() {
        if (roundParams == null) {
            return;
        }
        borderPath.setFillType(Path.FillType.WINDING);

        if (roundParams.roundAsCircle) {
            float radius = getMinSize() / 2;
            borderPath.moveTo(getWidth() / 2 - radius, getHeight() / 2);
            borderPath.addCircle(getWidth() / 2, getHeight() / 2, radius, Path.Direction.CW);
            //画内圆
            float inRadius = radius - roundParams.roundingBorderWidth;
            borderPath.moveTo(getWidth() / 2 - inRadius, getHeight() / 2);
            borderPath.addCircle(getWidth() / 2, getHeight() / 2, inRadius, Path.Direction.CCW);
            return;
        }

        final float radius = roundParams.getRoundCornerRadius();
        if (radius > 0 && isAnyCornerHasRound()) {
            //顺时针
            //左上角
            whenTopLeftRound(viewBound, borderPath, radius);
            //上直
            borderPath.lineTo(roundParams.isRoundTopRight ? viewBound.right - radius + radius : viewBound.right, viewBound.top);
            //右上角
            whenTopRightRound(viewBound, borderPath, radius);
            //右直
            borderPath.lineTo(viewBound.right, roundParams.isRoundBottomRight ? viewBound.bottom - radius : viewBound.bottom);
            //右下角
            whenBottomRightRound(viewBound, borderPath, radius);
            //下直
            borderPath.lineTo(roundParams.isRoundBottomLeft ? viewBound.left + radius : viewBound.left, viewBound.bottom);
            //左下角
            whenBottomLeftRound(viewBound, borderPath, radius);
            //左直
            borderPath.lineTo(viewBound.left, roundParams.isRoundTopLeft ? viewBound.top + radius : viewBound.top);

            final float inRadius = radius - roundParams.roundingBorderWidth;
            if (inRadius > 0) {
                //逆向
                //线移动
                borderPath.moveTo(roundParams.roundingBorderWidth, roundParams.roundingBorderWidth);
                //左直下
                borderPath.lineTo(inViewBound.left, roundParams.isRoundBottomLeft ? inViewBound.bottom - inRadius : inViewBound.bottom);
                //左下角
                whenBottomLeftRoundC(inViewBound, borderPath, inRadius);

                //下直右
                borderPath.lineTo(roundParams.isRoundBottomRight ? inViewBound.right - inRadius : inViewBound.right, inViewBound.bottom);
                //右下角
                whenBottomRightRoundC(inViewBound, borderPath, inRadius);

                //右直上
                borderPath.lineTo(inViewBound.right, roundParams.isRoundTopRight ? inViewBound.top + inRadius : inViewBound.top);
                //右上角
                whenTopRightRoundC(inViewBound, borderPath, inRadius);

                //上直左
                borderPath.lineTo(roundParams.isRoundTopLeft ? inViewBound.left + inRadius : inViewBound.left, inViewBound.top);
                //左上角
                whenTopLeftRoundC(inViewBound, borderPath, inRadius);

            }
        }

    }

    private void applyBound(@NonNull Canvas canvas, boolean obtainBounds, Path path) {
        if (obtainBounds) {
            canvas.clipPath(path);
        }
    }


    private void completed(@NonNull Canvas canvas) {
        canvas.restore();
        boundPath.reset();
        borderPath.reset();
    }


    private boolean isAnyCornerHasRound() {
        return roundEnable && (roundParams.isRoundTopLeft ||
                roundParams.isRoundTopRight ||
                roundParams.isRoundBottomLeft ||
                roundParams.isRoundBottomRight);
    }

    private void whenTopLeftRound(RectF rectF, Path path, Float radius) {
        if (roundParams.isRoundTopLeft) {
            pathArc.set(rectF.left, rectF.top, rectF.left + 2 * radius, rectF.top + 2 * radius);
            path.arcTo(pathArc, 180f, 90f);
        }
    }

    private void whenTopRightRound(RectF rectF, Path path, Float radius) {
        if (roundParams.isRoundTopRight) {
            pathArc.set(rectF.right - 2 * radius, rectF.top, rectF.right, rectF.top + 2 * radius);
            path.arcTo(pathArc, 270f, 90f);
        }
    }

    private void whenBottomRightRound(RectF rectF, Path path, Float radius) {
        if (roundParams.isRoundBottomRight) {
            pathArc.set(rectF.right - 2 * radius, rectF.bottom - 2 * radius, rectF.right, rectF.bottom);
            path.arcTo(pathArc, 0f, 90f);
        }
    }

    private void whenBottomLeftRound(RectF rectF, Path path, Float radius) {
        if (roundParams.isRoundBottomLeft) {
            pathArc.set(rectF.left, rectF.bottom - 2 * radius, rectF.left + 2 * radius, rectF.bottom);
            path.arcTo(pathArc, 90f, 90f);
        }
    }


    //逆时针 左上->左下
    private void whenBottomLeftRoundC(RectF rectF, Path path, Float radius) {
        if (roundParams.isRoundBottomLeft) {
            pathArc.set(rectF.left, rectF.bottom - 2 * radius, rectF.left + 2 * radius, rectF.bottom);
            path.arcTo(pathArc, 180f, -90f);
        }
    }

    //逆时针
    private void whenBottomRightRoundC(RectF rectF, Path path, Float radius) {
        if (roundParams.isRoundBottomRight) {
            pathArc.set(rectF.right - 2 * radius, rectF.bottom - 2 * radius, rectF.right, rectF.bottom);
            path.arcTo(pathArc, 90f, -90f);
        }
    }

    //逆时针
    private void whenTopRightRoundC(RectF rectF, Path path, Float radius) {
        if (roundParams.isRoundTopRight) {
            pathArc.set(rectF.right - 2 * radius, rectF.top, rectF.right, rectF.top + 2 * radius);
            path.arcTo(pathArc, 0f, -90f);
        }
    }

    //逆时针
    private void whenTopLeftRoundC(RectF rectF, Path path, Float radius) {
        if (roundParams.isRoundTopLeft) {
            pathArc.set(rectF.left, rectF.top, rectF.left + 2 * radius, rectF.top + 2 * radius);
            path.arcTo(pathArc, -90f, -90f);
        }
    }


    public void setRoundEnable(boolean enable) {
        roundEnable = enable;
        invalidate();
    }

    public RoundParams getRoundParams() {
        return roundParams;
    }

    public static class RoundParams {

        private final View view;

        boolean isClipBackground = true;

        boolean isClipForeground = true;
        /**
         * 是否是圆形
         */
        boolean roundAsCircle = false;
        /**
         * 圆角半径
         */
        float roundCornerRadius = 0f;
        /**
         * 左上圆角
         */
        boolean isRoundTopLeft = false;
        /**
         * 右上圆角
         */
        boolean isRoundTopRight = false;
        /**
         * 左下圆角
         */
        boolean isRoundBottomLeft = false;
        /**
         * 右下圆角
         */
        boolean isRoundBottomRight = false;

        /**
         * 边界
         */
        boolean isBorderEnable = false;
        /**
         * 圆角边界宽度
         */
        float roundingBorderWidth = 0f;
        /**
         * 圆角边界颜色
         */
        int roundingBorderColor = 0;


        public RoundParams(View view) {
            this.view = view;
        }

        public View getView() {
            return view;
        }

        public boolean isClipBackground() {
            return isClipBackground;
        }

        public void setClipBackground(boolean clipBackground) {
            isClipBackground = clipBackground;
            updateView();
        }

        public boolean isClipForeground() {
            return isClipForeground;
        }

        public void setClipForeground(boolean clipForeground) {
            isClipForeground = clipForeground;
            updateView();
        }

        public boolean isRoundAsCircle() {
            return roundAsCircle;
        }

        public void setRoundAsCircle(boolean roundAsCircle) {
            this.roundAsCircle = roundAsCircle;
            updateView();
        }

        public boolean isBorderEnable() {
            return isBorderEnable;
        }

        public void setBorderEnable(boolean borderEnable) {
            isBorderEnable = borderEnable;
        }

        public float getRoundCornerRadius() {
            return roundCornerRadius;
        }

        public void setRoundCornerRadius(float roundCornerRadius) {
            this.roundCornerRadius = roundCornerRadius;
            updateView();
        }

        public boolean isRoundTopLeft() {
            return isRoundTopLeft;
        }

        public void setRoundTopLeft(boolean roundTopLeft) {
            isRoundTopLeft = roundTopLeft;
            updateView();
        }

        public boolean isRoundTopRight() {
            return isRoundTopRight;
        }

        public void setRoundTopRight(boolean roundTopRight) {
            isRoundTopRight = roundTopRight;
            updateView();
        }

        public boolean isRoundBottomLeft() {
            return isRoundBottomLeft;
        }

        public void setRoundBottomLeft(boolean roundBottomLeft) {
            isRoundBottomLeft = roundBottomLeft;
            updateView();
        }

        public boolean isRoundBottomRight() {
            return isRoundBottomRight;
        }

        public void setRoundBottomRight(boolean roundBottomRight) {
            isRoundBottomRight = roundBottomRight;
            updateView();
        }

        public float getRoundingBorderWidth() {
            return roundingBorderWidth;
        }

        public void setRoundingBorderWidth(float roundingBorderWidth) {
            this.roundingBorderWidth = roundingBorderWidth;
            updateView();
        }

        public int getRoundingBorderColor() {
            return roundingBorderColor;
        }

        public void setRoundingBorderColor(int roundingBorderColor) {
            this.roundingBorderColor = roundingBorderColor;
            updateView();
        }

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        private void updateView() {
            if (view.isAttachedToWindow()) {
                view.invalidate();
            }
        }
    }
}
